//#define XP_UNIX
#include "jsapi.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fatal(const char *str) {
	fprintf(stderr, "FATAL: %s\n", str);
	exit(1);
}

void trace(const char *str) {
	printf("*** %s\n", str);
}



jsval eval(JSContext *cx, const char *code, const char *filename, int lineno) {
	if(!filename)
		filename = "<eval>";		
	if(!lineno)
		lineno = 1;
	jsval rval = JSVAL_VOID;
	JSScript *script;
	JS_BeginRequest(cx);
	script = JS_CompileScript(cx, JS_GetGlobalObject(cx), code, strlen(code), filename, lineno);
	JS_EndRequest(cx);
	if (!script)
		fatal("compile script failed");
	JS_BeginRequest(cx);
	JS_ExecuteScript(cx, JS_GetGlobalObject(cx), script, &rval);
	JS_DestroyScript(cx, script);
	JS_EndRequest(cx);
	return rval;
}

JSClass global_class = {
    "global", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE,
    JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub,
    JS_PropertyStub,
//    JS_StrictPropertyStub,
    JS_EnumerateStub, JS_ResolveStub,  JS_ConvertStub,   JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};

void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
	fprintf(stderr, "%s:%u:%s\n",
		report->filename ? report->filename : "<no filename>",
		(unsigned int) report->lineno,
		message
	);
}

static JSBool
global_print(JSContext *cx, uintN argc, jsval *vp) {
	jsval *argv = JS_ARGV(cx, vp);
	JSString *s = JS_ValueToString(cx, argv[0]);
	char *bytes = JS_EncodeString(cx, s);
	if (!bytes)
		return JS_FALSE;
	printf("%s\n", bytes);
	JS_free(cx, bytes);
	JS_SET_RVAL(cx, vp, JSVAL_VOID);
	return JS_TRUE;
}


static JSFunctionSpec global_functions[] = {
	JS_FN("print",  global_print, 1, 0),
	JS_FS_END
};


int main(int argc, const char *argv[]) {
	JSRuntime *rt;
	JSContext *cx;
	JSObject  *global;

	rt = JS_NewRuntime(8L * 1024L * 1024L);
	if (rt == NULL)
		return 1;

	cx = JS_NewContext(rt, 8192);
	if (cx == NULL)
		return 1;

	JS_SetOptions(cx, JSOPTION_DONT_REPORT_UNCAUGHT | JSOPTION_COMPILE_N_GO | JSOPTION_ATLINE | JSOPTION_JIT);	
	JS_SetVersion(cx, JSVERSION_LATEST);
	JS_SetErrorReporter(cx, reportError);
	
	JS_BeginRequest(cx);
#if JS_VERSION > 180	
#warning "js is new!"
		global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
#else		
		global = JS_NewObject(cx, &global_class, NULL, NULL);
#endif		
		//global = JS_NewGlobalObject(cx, &global_class);
		JS_DefineFunctions(cx, global, global_functions);
		JS_InitStandardClasses(cx, global);
		JS_SetGlobalObject(cx, global);		
	JS_EndRequest(cx);

//	eval(cx, "print('denis', 22)", "<eval>", 0);
//	return 0;
	
	eval(cx, "\
(function() {\
	var t0 = +new Date, x = 0;\
	for (var i = 0; i < 10000000; ++i)\
		x = (x + i) % 987;\
	print('x=' + x);\
	var t = (+new Date) - t0;\
	print('Execution time: ' + t + ' ms.');\
})();\
	", "<eval>", 0);


	/* Cleanup. */
	JS_DestroyContext(cx);
	JS_DestroyRuntime(rt);
	JS_ShutDown();
	return 0;
}
